/// @Classname : HcCalendar
/// @Author :
/// @Time : 2024-02-19 14:07
/// @Description : //todo

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:hc_ui/config/hc_customer_config.dart';
import 'package:hc_ui/theme/hc_common_theme.dart';
import 'package:hc_ui/utils/hc_color_util.dart';
import 'package:hc_ui/widget/grid/hc_grid.dart';

import 'calendar_bean.dart';

typedef HcCalendarFormatter = HcCalendarDay Function(HcCalendarDay);
typedef HcCalendarSelect = Function(HcCalendarSelectResult);
//标题列表
List<String> _weekTitle = ["日", "一", "二", "三", "四", "五", "六"];
//默认起始时间
DateTime _defaultStartDate = DateTime(1970, 01, 01, 0, 0, 0, 0);
//默认最大时间
DateTime _defaultEndDate = DateTime(2099, 12, 31, 0, 0, 0, 0);

class HcCalendar extends StatefulWidget {
  //起始时间
  final DateTime? minDate;

  //结束时间
  final DateTime? maxDate;

  //一周的起点
  final int firstDayOfWeek;

  //是否展示今天
  final bool showToday;

  //是否展示月份的水印
  final bool showMonthMark;

  //是否只展示当前月份
  final bool onlyShowCurrentMonth;

  //最大选择长度
  final int maxLength;

  //默认选择的日期
  final List<DateTime>? defaultValue;

  //选择方式
  final HcCalendarSelectMode selectMode;

  //日期格式化
  final HcCalendarFormatter? formatter;

  //选中的结果
  final HcCalendarSelect select;

  //选中的颜色
  final Color selectColor;

  //横轴间距
  final double mainAxisSpacing;

  //纵轴间距
  final double crossAxisSpacing;

  //阴影颜色
  final Color shadowColor;

  //只读
  final bool readOnly;

  const HcCalendar(
      {Key? key,
      this.minDate,
      this.maxDate,
      this.firstDayOfWeek = 0,
      this.showToday = true,
      this.showMonthMark = true,
      this.onlyShowCurrentMonth = false,
      this.maxLength = -1,
      this.defaultValue,
      this.selectMode = HcCalendarSelectMode.single,
      this.formatter,
      required this.select,
      this.selectColor = Colors.blue,
      this.mainAxisSpacing = 5,
      this.crossAxisSpacing = 5,
      this.shadowColor = const Color.fromRGBO(125, 126, 128, 0.16),
      this.readOnly = false})
      : super(key: key);

  @override
  State<HcCalendar> createState() => _HcCalendarState();
}

class _HcCalendarState extends State<HcCalendar> {
  DateTime currentDateValue =
      DateTime(DateTime.now().year, DateTime.now().month);
  DateTime startDate = _defaultStartDate;
  DateTime endDate = _defaultEndDate;
  List<HcCalendarDay> dataList = [];
  List<DateTime> selectList = [];
  bool showPreMonth = true;
  bool showNextMonth = true;
  bool showTodayBtn = true;
  String currentMonth =
      '${DateTime.now().month > 9 ? '' : '0'}${DateTime.now().month}';

  @override
  void initState() {
    super.initState();
    _initData();
  }

  @override
  void didUpdateWidget(covariant HcCalendar oldWidget) {
    // TODO: implement didUpdateWidget
    super.didUpdateWidget(oldWidget);
    _initData();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.max,
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        _buildCalNavBar(),
        _buildCalWeekTitle(),
        _buildCalDayContent(),
      ],
    );
  }

  //顶部导航栏
  _buildCalNavBar() {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 5),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: [
          InkWell(
            onTap:
                showPreMonth ? () => _changeMonth(type: MonthType.pre) : null,
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
              child: Icon(
                Icons.arrow_back_ios_new,
                size: 16,
                color: showPreMonth ? Colors.black : Colors.black12,
              ),
            ),
          ),
          Expanded(
              child: Stack(
            children: [
              Padding(
                padding: const EdgeInsets.all(10),
                child: Center(
                  child: Text(_formatterDay(
                      dateTime: currentDateValue,
                      separator: 'chinese',
                      digit: 2)),
                ),
              ),
              if (showTodayBtn)
                Positioned(
                  right: 0,
                  top: 0,
                  child: InkWell(
                    onTap: () => _goToday(),
                    child: const Padding(
                      padding: EdgeInsets.all(10),
                      child: Text('今'),
                    ),
                  ),
                )
            ],
          )),
          InkWell(
            onTap:
                showNextMonth ? () => _changeMonth(type: MonthType.next) : null,
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
              child: Icon(
                Icons.arrow_forward_ios_outlined,
                size: 16,
                color: showNextMonth ? Colors.black : Colors.black12,
              ),
            ),
          ),
        ],
      ),
    );
  }

  //星期组件
  _buildCalWeekTitle() {
    return Material(
      elevation: 2,
      shadowColor: widget.shadowColor,
      child: Container(
        padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
        child: HcGrid(
          mainAxisSpacing: widget.mainAxisSpacing,
          crossAxisSpacing: widget.crossAxisSpacing,
          itemBuilder: (BuildContext context, int index) {
            return SizedBox(
              width: double.infinity,
              child: Text(
                _weekTitle[(index + widget.firstDayOfWeek) % 7],
                textAlign: TextAlign.center,
                style: const TextStyle(fontSize: 14),
              ),
            );
          },
          crossAxisCount: 7,
          itemCount: 7,
        ),
      ),
    );
  }

  //正文内容
  _buildCalDayContent() {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
      decoration: const BoxDecoration(),
      child: Stack(
        children: [
          if (widget.showMonthMark)
            Positioned.fill(
              top: 0,
              left: 0,
              child: Center(
                child: Text(
                  '${currentDateValue.month > 9 ? '' : '0'}${currentDateValue.month}',
                  style: const TextStyle(
                      fontSize: 160, color: Color.fromRGBO(242, 243, 245, 0.8)),
                ),
              ),
            ),
          HcGrid(
            mainAxisSpacing: widget.mainAxisSpacing,
            crossAxisSpacing: widget.crossAxisSpacing,
            itemBuilder: (BuildContext context, int index) {
              return Opacity(
                opacity:
                    dataList[index].monthType == MonthType.current ? 1 : 0.6,
                child: Ink(
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: InkWell(
                    borderRadius: BorderRadius.circular(8),
                    onTap: _onTap(index),
                    child: AspectRatio(
                      aspectRatio: 1 / 1,
                      child: Container(
                        decoration: _itemDecoration(index),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          mainAxisAlignment: MainAxisAlignment.center,
                          crossAxisAlignment: CrossAxisAlignment.center,
                          children: [
                            Text(
                              dataList[index].topText,
                              textAlign: TextAlign.center,
                              style: _textStyle(index, 10),
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                            ),
                            Text(
                              dataList[index].text,
                              textAlign: TextAlign.center,
                              style: _textStyle(index, 14),
                            ),
                            Text(
                              dataList[index].bottomText,
                              textAlign: TextAlign.center,
                              style: _textStyle(index, 10),
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                            )
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              );
            },
            crossAxisCount: 7,
            itemCount: dataList.length,
          )
        ],
      ),
    );
  }

  GestureTapCallback? _onTap(int index) {
    return dataList[index].dayStatus == HcCalendarDayStatus.disabled ||
            (dataList[index].monthType == MonthType.pre &&
                (!showPreMonth || widget.onlyShowCurrentMonth)) ||
            (dataList[index].monthType == MonthType.next &&
                (!showNextMonth || widget.onlyShowCurrentMonth))
        ? null
        : () => _clickItem(dataList[index]);
  }

  BoxDecoration? _itemDecoration(int index) {
    if (dataList[index].dayStatus == HcCalendarDayStatus.selected ||
        dataList[index].dayStatus == HcCalendarDayStatus.middle) {
      return BoxDecoration(
        borderRadius: _checkBorderRadius(index),
        color: HcCustomerConfig().allTheme.commonTheme.primaryColor.withOpacity(
            dataList[index].dayStatus == HcCalendarDayStatus.middle ? 0.6 : 1),
        // color: Colors.grey,
      );
    }
    return null;
  }

  ///补全本月天数
  void _getAllDay() {
    List<HcCalendarDay> temp = [];
    // 当前月起始星期数
    int weekday =
        DateTime(currentDateValue.year, currentDateValue.month, 1).weekday;
    // 查询本有多少天
    int currentMonthDays =
        DateTime(currentDateValue.year, currentDateValue.month + 1, 0).day;
    //查询上个月右多少天
    int preMonthDays =
        DateTime(currentDateValue.year, currentDateValue.month, 0).day;
    //查询上个月需要补多少天
    int preNeedDays = (7 + weekday - widget.firstDayOfWeek) % 7;
    for (int i = preMonthDays - preNeedDays; i < preMonthDays; i++) {
      HcCalendarDay day = HcCalendarDay(
          day: DateTime(
              currentDateValue.year, currentDateValue.month - 1, i + 1),
          text: widget.onlyShowCurrentMonth ? '' : '${i + 1}',
          monthType: MonthType.pre);
      temp.add(day);
    }
    for (int i = 0; i < currentMonthDays; i++) {
      DateTime sDate = _formatterTime(startDate);
      DateTime eDate = _formatterTime(endDate);
      DateTime nDate = _formatterTime(DateTime.now());
      DateTime cDate =
          DateTime(currentDateValue.year, currentDateValue.month, i + 1);
      HcCalendarDay day = HcCalendarDay(
          day: cDate, text: '${i + 1}', monthType: MonthType.current);
      //在区间外禁止
      if (sDate.isAfter(cDate) || eDate.isBefore(cDate)) {
        day.dayStatus = HcCalendarDayStatus.disabled;
      }
      //是不是当天
      if (cDate.isAtSameMomentAs(nDate)) {
        day.topText = "今日";
      }
      if (widget.formatter != null) {
        HcCalendarDay temp = widget.formatter!.call(day);
        day.assign(
            day: temp.day,
            text: temp.text,
            topText: temp.topText,
            bottomText: temp.bottomText,
            dayStatus: temp.dayStatus);
      }
      int sIndex = selectList.indexOf(day.day);
      if (day.dayStatus == HcCalendarDayStatus.disabled && sIndex != -1) {
        selectList.removeAt(sIndex);
      }
      for (var element in selectList) {
        element = _formatterTime(element);
        if (element == day.day &&
            day.dayStatus != HcCalendarDayStatus.disabled) {
          day.dayStatus = HcCalendarDayStatus.selected;
        }
      }
      if (sIndex != -1 && widget.selectMode == HcCalendarSelectMode.range) {
        day.topText = sIndex > 0 ? '结束' : '开始';
        print("${day.day}");
        print("${selectList.first}");
      }
      if (widget.selectMode == HcCalendarSelectMode.range &&
          selectList.length == 2 &&
          day.day.isAfter(selectList.first) &&
          day.day.isBefore(selectList.last) &&
          day.dayStatus != HcCalendarDayStatus.disabled) {
        day.dayStatus = HcCalendarDayStatus.middle;
      }
      temp.add(day);
    } // 补全下个月天数
    for (int i = 0; i < 42 - currentMonthDays - preNeedDays; i++) {
      HcCalendarDay day = HcCalendarDay(
          day: DateTime(
              currentDateValue.year, currentDateValue.month + 1, i + 1),
          text: widget.onlyShowCurrentMonth ? '' : '${i + 1}',
          monthType: MonthType.next);
      temp.add(day);
    }
    setState(() {
      showNextMonth =
          endDate.copyWith(day: 1).isAfter(currentDateValue.copyWith(day: 1));
      showPreMonth = startDate
          .copyWith(day: 1)
          .isBefore(currentDateValue.copyWith(day: 1));
      dataList = temp;
      showTodayBtn = widget.showToday &&
          !_formatterTime(currentDateValue).isAtSameMomentAs(
              _formatterTime(DateTime.now().copyWith(day: 1)));
    });
  }

  //点击条目
  _clickItem(HcCalendarDay day) {
    List<DateTime> oldSelectList = selectList.toList();
    int index = selectList.indexOf(day.day);
    //当前月 禁止点击项
    if (day.monthType == MonthType.current &&
        (day.dayStatus == HcCalendarDayStatus.disabled || widget.readOnly)) {
      return;
    }
    if (!widget.readOnly) {
      switch (widget.selectMode) {
        case HcCalendarSelectMode.single:
          selectList = [day.day];
          break;
        case HcCalendarSelectMode.multiple:
          if (widget.maxLength != -1 &&
              selectList.length >= widget.maxLength &&
              index == -1) {
            print("超出最大选择范围");
          } else if (index != -1) {
            selectList.removeAt(index);
          } else {
            selectList.add(day.day);
          }
          break;
        case HcCalendarSelectMode.range:
          //空的就直接填入
          if (selectList.isEmpty) {
            selectList.add(day.day);
          } else {
            //存在需要移除
            if (index != -1) {
              selectList.removeAt(index);
            } else {
              int diff =
                  _formatterTime(day.day).difference(selectList[0]).inDays;
              print("差距多少天$diff");
              //时间小于选择的时间 或者当前列表已经选择两个时间了
              if (diff.sign == -1 || selectList.length > 1) {
                selectList = [day.day];
              } else if (widget.maxLength == -1 || diff < widget.maxLength) {
                //  在时间内 或者最大长度没设定
                selectList.add(day.day);
              } else {
                //  超过长度外则取最大长度
                print("超过最大选择长度!");
                selectList.add(selectList[0]
                    .copyWith(day: selectList[0].day + widget.maxLength - 1));
              }
            }
          }
          break;
      }
      selectList.sort((a, b) => a.difference(b).inMicroseconds);
    }
    setState(() {
      currentDateValue = day.day.copyWith(day: 1);
    });
    _getAllDay();
    //新老列表有变化就返回新值
    if (selectList
        .toSet()
        .difference(oldSelectList.toSet())
        .toList()
        .isNotEmpty) {
      widget.select.call(HcCalendarSelectResult(
          mode: widget.selectMode, resultList: selectList));
    }
  }

  //格式化时间
  _formatterDay({required DateTime dateTime, separator = "/", digit = 3}) {
    int cYear = dateTime.year;
    int cMonth = dateTime.month;
    int cDay = dateTime.day;
    String cYearStr = '$cYear';
    String cMonthStr = '${cMonth > 9 ? '' : '0'}$cMonth';
    String cDayStr = '${cDay > 9 ? '' : '0'}$cDay';
    if (separator == 'chinese') {
      cYearStr = '$cYearStr年';
      cMonthStr = '$cMonthStr月';
      cDayStr = "$cDayStr日";
    }
    List<String> result =
        [cYearStr, cMonthStr, cDayStr].sublist(0, max(0, min(digit, 3)));
    if (separator != 'chinese') {
      return result.join(separator);
    }

    return result.join(separator != 'chinese' ? separator : '');
  }

  /// 切换月份
  /// [type] 上/下一月
  _changeMonth({required MonthType type}) {
    setState(() {
      currentDateValue = currentDateValue.copyWith(
          month: currentDateValue.month + (type == MonthType.pre ? -1 : 1));
    });
    _getAllDay();
  }

  ///初始化数据
  void _initData() {
    selectList = widget.defaultValue ?? [_formatterTime(DateTime.now())];
    selectList.where(
        (element) => element.isAfter(startDate) && element.isBefore(endDate));
    if (widget.selectMode == HcCalendarSelectMode.single &&
        selectList.isNotEmpty) {
      selectList = selectList.sublist(0);
    }
    if (widget.selectMode == HcCalendarSelectMode.range &&
        selectList.isNotEmpty) {
      selectList = [selectList.first, selectList.last];
    }
    setState(() {
      currentDateValue =
          selectList.isNotEmpty ? selectList.first : currentDateValue;
      startDate = widget.minDate ?? _defaultStartDate;
      endDate = widget.maxDate ?? _defaultEndDate;
      selectList = selectList;
    });
    _getAllDay();
  }

  DateTime _formatterTime(DateTime dataTime) {
    return dataTime.copyWith(
        hour: 0, minute: 0, second: 0, microsecond: 0, millisecond: 0);
  }

  TextStyle _textStyle(int index, double fontSize) {
    return TextStyle(
        fontSize: fontSize,
        color: dataList[index].monthType == MonthType.current &&
                dataList[index].dayStatus != HcCalendarDayStatus.disabled
            ? HcColorUtil.needLightColor(
                    dataList[index].dayStatus == HcCalendarDayStatus.selected
                        ? widget.selectColor
                        : Colors.transparent)
                ? HcCommonTheme().textInverseColor
                : HcCommonTheme().textBaseColor
            : HcCommonTheme().textDisableColor);
  }

  _goToday() {
    setState(() {
      currentDateValue = _formatterTime(DateTime.now().copyWith(day: 1));
    });
    _getAllDay();
  }

  BorderRadius _checkBorderRadius(int index) {
    BorderRadius result = const BorderRadius.all(Radius.circular(8));
    if (widget.crossAxisSpacing == 0) {
      if (index + 1 < dataList.length &&
          (dataList[index + 1].dayStatus == HcCalendarDayStatus.selected ||
              dataList[index + 1].dayStatus == HcCalendarDayStatus.middle) &&
          index % 7 != 6) {
        result =
            result.copyWith(topRight: Radius.zero, bottomRight: Radius.zero);
      }
      print(index % 7);
      if (index >= 1 &&
          (dataList[index - 1].dayStatus == HcCalendarDayStatus.selected ||
              dataList[index - 1].dayStatus == HcCalendarDayStatus.middle) &&
          index % 7 != 0) {
        result = result.copyWith(topLeft: Radius.zero, bottomLeft: Radius.zero);
      }
    }
    if (widget.mainAxisSpacing == 0) {
      if (index + 7 < dataList.length &&
          (dataList[index + 7].dayStatus == HcCalendarDayStatus.selected ||
              dataList[index + 7].dayStatus == HcCalendarDayStatus.middle)) {
        result =
            result.copyWith(bottomLeft: Radius.zero, bottomRight: Radius.zero);
      }
      if (index >= 7 &&
          (dataList[index - 7].dayStatus == HcCalendarDayStatus.selected ||
              dataList[index - 7].dayStatus == HcCalendarDayStatus.middle)) {
        result = result.copyWith(topLeft: Radius.zero, topRight: Radius.zero);
      }
    }
    return result;
  }
}
